/* Created on Jul 11, 2007 */
/**
 * 
 */
package com.xbang.core.utils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import com.xbang.core.dao.search.component.SearchContext;
import com.xbang.core.dao.search.dialect.SearchDialect;

/**
 * Search Utilities for searchComponent
 * 
 * @author dev.zhang
 */
public abstract class SearchUtils {

	public static List COMPARE_OPERATORS = Arrays.asList(new String[] { "eq", "neq", "gt", "lt", "geq", "leq", "like", "in" });

	public static List ORDER_OPERATORS = Arrays.asList(new String[] { "orderby" });

	public static List GROUP_OPERATORS = Arrays.asList(new String[] { "groupby" });

	public static Map OPERATION_MAPPING = new HashMap();

	public static Map<String, String> OPERATION_MAPPING_NOTE = new HashMap<String, String>();

	static {
		// register operations
		OPERATION_MAPPING.put("eq", " = ");
		OPERATION_MAPPING.put("neq", " <> ");
		OPERATION_MAPPING.put("gt", " > ");
		OPERATION_MAPPING.put("lt", " < ");
		OPERATION_MAPPING.put("geq", " >= ");
		OPERATION_MAPPING.put("leq", " <= ");
		OPERATION_MAPPING.put("like", " LIKE ");
		OPERATION_MAPPING.put("in", " IN ");
		OPERATION_MAPPING.put("orderby", " ORDER BY ");
		OPERATION_MAPPING.put("groupby", " GROUP BY ");

		// /register operations by note.
		OPERATION_MAPPING_NOTE.put("eq", " 等于 ");
		OPERATION_MAPPING_NOTE.put("neq", " 不等于 ");
		OPERATION_MAPPING_NOTE.put("gt", " 大于 ");
		OPERATION_MAPPING_NOTE.put("lt", " 小于 ");
		OPERATION_MAPPING_NOTE.put("geq", " 大于等于 ");
		OPERATION_MAPPING_NOTE.put("leq", " 小于等于 ");
		OPERATION_MAPPING_NOTE.put("like", " 类似 ");
		OPERATION_MAPPING_NOTE.put("in", " 包含于 ");
		OPERATION_MAPPING_NOTE.put("orderby", " 排序 ");
		OPERATION_MAPPING_NOTE.put("groupby", " 分组 ");
	}

	/**
	 * Get namedParameters according to the sentence and parameters
	 * 
	 * @param sentence
	 * @param parameters
	 * @return
	 */
	public static Map<String, Object> getNamedParameters(String sentence, Object... parameters) {
		Map<String, Object> result = new HashMap<String, Object>();
		List<String> namedParameterString = SearchUtils.getIdentifiedString(sentence, ":");

		if (namedParameterString.size() != parameters.length) {
			throw new RuntimeException("QuerySentence do not match parameters.");
		} else {
			for (int i = 0; i < namedParameterString.size(); i++) {
				result.put(namedParameterString.get(i), parameters[i]);
			}
		}

		return result;
	}

	/**
	 * 
	 * @param expression
	 * @param identifier
	 * @return
	 */
	public static List<String> getIdentifiedString(String expression, String identifier) {
		List<String> result = new ArrayList<String>();

		int length = expression.length();
		int index = expression.indexOf(identifier);
		int blank = expression.indexOf(" ", index) == -1 ? length : expression.indexOf(" ", index);

		while (index != -1 && index < length) {

			String temp = expression.substring(index + 1, blank);
			result.add(temp);

			index = expression.indexOf(identifier, blank);
			blank = expression.indexOf(" ", index) == -1 ? length : expression.indexOf(" ", index);
		}

		return result;
	}

	/**
	 * 
	 * @param searchContext
	 * @param value
	 * @return
	 */
	public static String getSentence(SearchContext searchContext, Object value) {
		StringBuffer sb = new StringBuffer();
		if (searchContext.isOrderSentence()) {
			sb.append(searchContext.getTarget());
			sb.append(" ").append(value.toString());
		} else if (searchContext.isGroupSentence()) {
			sb.append(searchContext.getTarget());
		} else {
			sb.append(" AND (");
			sb.append(searchContext.getTarget());
			sb.append(OPERATION_MAPPING.get(searchContext.getOperation()));
			if (searchContext.getOperation().toLowerCase().equals("in")) {
				sb.append("(:").append(searchContext.getParameterKey()).append(")");
			} else {
				sb.append(":").append(searchContext.getParameterKey());
			}
			sb.append(")");
		}
		return sb.toString();
	}

	/**
	 * Determine whether the searchContext is a order sentence
	 * 
	 * @param searchContext
	 * @return
	 */
	public static boolean isOrderSentence(String operation) {
		return ORDER_OPERATORS.contains(operation);
	}

	/**
	 * Determine whether the searchContext is a group sentence
	 * 
	 * @param operation
	 * @return
	 */
	public static boolean isGroupSentence(String operation) {
		return GROUP_OPERATORS.contains(operation);
	}

	/**
	 * Determine whether the searchContext is a where sentence
	 * 
	 * @param operation
	 * @return
	 */
	public static boolean isWhereSentence(String operation) {
		return COMPARE_OPERATORS.contains(operation);
	}

	/**
	 * Determine whether the operation is valid
	 * 
	 * @param operation
	 * @return
	 */
	public static boolean isOperationValid(String operation) {
		return isOrderSentence(operation) || isGroupSentence(operation) || isWhereSentence(operation);
	}

	/**
	 * Get limited sentence for a basic query sentence according to the dialect
	 * 
	 * @param sentence
	 * @param dialect
	 * @param beginIndex
	 * @param maxResult
	 * @return
	 */
	public static String getLimitedSentence(SearchDialect dialect, String sentence, int beginIndex, int maxResult, boolean putValue) {
		return dialect.getSearchLimitString(sentence, beginIndex, maxResult, putValue);
	}

	/**
	 * Generate HQL count sentence
	 * 
	 * @param persistentClass
	 * @return
	 */
	public static String getHQLCountSentence(Class<?> persistentClass) {
		String querySentence = getQuerySentence(persistentClass);
		return getHQLCountSentence(querySentence);
	}

	/**
	 * 
	 * @param sentence
	 * @return
	 */
	public static String getHQLCountSentence(String sentence) {
		StringBuffer sb = new StringBuffer("SELECT count(*) ");
		String tempSentence = StringUtils.trim(sentence).toUpperCase();
		if (tempSentence.startsWith("FROM")) {
			return sb.append(sentence).toString();
		} else {
			int index = tempSentence.indexOf(" FROM ");
			return sb.append(sentence.substring(index)).toString();
		}
	}

	/**
	 * 
	 * @param sentence
	 * @return
	 */
	public static String getSQLCountSentence(String sentence) {
		StringBuffer sb = new StringBuffer("SELECT count(*) FROM (");
		return sb.append(sentence).append(") countTemp_").toString();
	}

	/**
	 * 
	 * @param persistentClass
	 * @return
	 */
	public static String getCountSentence(Class persistentClass) {
		String querySentence = getQuerySentence(persistentClass);
		return getHQLCountSentence(querySentence);
	}

	/**
	 * 
	 * @param persistentClass
	 * @return
	 */
	public static String getQuerySentence(Class persistentClass) {
		String persistentClassName = getPersistentClassName(persistentClass);
		StringBuffer querySentence = new StringBuffer();
		querySentence.append("FROM ").append(persistentClassName);
		querySentence.append(" ").append(getAlias(persistentClass)).append(" ");
		return querySentence.toString();
	}

	/**
	 * 
	 * @param persistentClass
	 * @return
	 */
	public static String getAlias(Class persistentClass) {
		String persistentClassName = getPersistentClassName(persistentClass);
		return persistentClassName.substring(0, 1).toLowerCase() + persistentClassName.substring(1);
	}

	/**
	 * 
	 * @param persistentClass
	 * @return
	 */
	public static String getPersistentClassName(Class persistentClass) {
		return persistentClass.getName().substring(persistentClass.getName().lastIndexOf(".") + 1);
	}

}
